//----------------------------------------------------------------------------
//  ,-.
// /_\___ ,   Ninja Framework
// '  ___\    (C) Riccardo Capra - http://riccar.do
//  //   \\
//----------------------------------------------------------------------------
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

#ifndef NJ_EVENTS_SYSTEM_LINUX_H
#	define NJ_EVENTS_SYSTEM_LINUX_H

#	include "NjExample01.h"

#	if NJ_PLATFORM_OS_LINUX
	/// \brief The default Linux implementation for NjEventsSystem
	class NjEventsSystemLinux : public NjEventsSystem::Implementation
	{
	public:
		/// \brief Creates an NjEventsSystemLinux instance
		NjEventsSystemLinux();

		/// \brief Destroys this NjEventsSystemLinux instance
		///
		/// On some build configurations assertions will be triggered if not all the created events has been distroyed before this call
		virtual ~NjEventsSystemLinux();

		/// \brief Releases spare Events that are currently not used
		void FlushCache();

	protected:
		/// \copydoc NjEventsSystem::Event
		typedef NjEventsSystem::Event Event;

		/// \copydoc NjEventsSystem::TryResult
		typedef NjEventsSystem::TryResult TryResult;

		/// \copydoc NjEventsSystem::TimeMs
		typedef NjEventsSystem::TimeMs TimeMs;

		/// \copydoc NjEventsSystem::Implementation::CreateEvent
		virtual Event * CreateEvent(NjBool bSet);

		/// \copydoc NjEventsSystem::Implementation::TryWaitEvent
		virtual TryResult TryWaitEvent(Event * pEvent, TimeMs uTimeMs);

		/// \copydoc NjEventsSystem::Implementation::SetEvent
		virtual NjBool SetEvent(Event * pEvent);

		/// \copydoc NjEventsSystem::Implementation::UnsetEvent
		virtual NjBool UnsetEvent(Event * pEvent);

		/// \copydoc NjEventsSystem::Implementation::DestroyEvent
		virtual NjBool DestroyEvent(Event * pEvent);

		/// \brief Returns current thread Id
		/// \return Always NJ_TRUE
		virtual NjBool GetCurrentThreadDebugId(NjUint & uDebugId);

		/// \brief Returns current time in milliseconds
		/// \return Always NJ_TRUE
		virtual NjBool GetTimeMs(TimeMs & uTimeMs);

		/// \brief Updates \em uSpinCount to \em m_uSpinCount
		/// \return Always NJ_TRUE
		virtual NjBool GetSpinCount(NjUint & uSpinCount);

	private:
		/// \brief Private class for internal use
		class Static;

		/// \brief NjEventsSystemLinux implementation for Event type
		class EventImpl;

		/// \brief Spare events
		NjAtomicStack m_kFreeEvents;

#if NJ_ASSERT_ENABLED
		/// \brief Counts how many events has been requested to the operating system
		///
		/// When events are returned to the operating system through a FlushCache, this number is decremented accordingly
		NjAtomic<NjUint> m_kTotEvents;
#endif // NJ_ASSERT_ENABLED

		/// \brief Set to 1 on single core hardware and to Static::DEFAULT_SPIN_COUNT on multicore hardware
		NjUint m_uSpinCount;

		NJ_DISABLE_COPY(NjEventsSystemLinux);
	};

	/// \brief Default platform specific implementation of NjEventsSystem
	typedef NjEventsSystemLinux NjEventsSystemPlatform;
#	endif // NJ_PLATFORM_OS_LINUX

#endif // NJ_EVENTS_SYSTEM_WIN_H
